﻿using System.Collections.Generic;
using System.Linq;

using System.ComponentModel;
using System.Threading;
using App.Business.Entities.Party;
using App.Business.Party;
using EntityAop.Extensions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RrslLite.Configuration;
using RrslLite.Dsl;
using RrslLite.Net;
using RrslLite.Net.Attributes;
using RrslLite.Net.BatchImpl;
using RrslLite.Net.Proxies;

namespace App.Test.RrslLiteTEST
{
	/// <summary>
	/// Summary description for BatchFactoryTEST
	/// </summary>
	[TestClass]
	public class BatchFactoryTest
	{

		[TestInitialize]
		public void Init()
		{
            RrslLiteConfiguration.Instance.WithDefaultBatchBuilderConfiguration();

            RrslLiteConfiguration.Instance.BatchBuilderConfiguration
                .WithCreateClassProxyWithTargetRecursiveToReceiveMessages()
                .WithINotifyPropertyChangedInterceptorToReceiveMessages()
                ;

			KnownTypeProvider.RegisterModelDomainNamespace("App.Business.Entities");
		}

		[TestMethod]
		public void AOPNewFactoryAsync_FluentConfiguration()
		{
			var @eventCall1 = new ManualResetEvent(false);
			var @eventCall2 = new ManualResetEvent(false);
			var @eventCall3 = new ManualResetEvent(false);

			IBatchBuilder factory = new AsyncBatchBuilder();

			factory
				.Call<IPersonFacade>()
					.WithQuery(f => f.GetActivePersonsFor("CZ"), list =>
					{
						Assert.IsNotNull(list);
                        @eventCall1.Set();
					})
					.WithQuery(f => f.GetMostImportantPersonFor("DE"), person =>
					{
						Assert.IsNotNull(person);
                        @eventCall2.Set();
					})
				.Call<ICountryFacade>()
					.WithQuery(f => f.GetByCode("CZ"), country =>
					{
						Assert.IsNotNull(country);
                        @eventCall3.Set();
					})
			.Execute();

			@eventCall1.WaitOne();
			@eventCall2.WaitOne();
			@eventCall3.WaitOne();
			//WaitHandle.WaitAll(new[] {@eventCall1, @eventCall2} );
		}

        [TestMethod]
        public void BatchFactoryAsync_Using_RrslConfiguration()
        {
            var @eventCall1 = new ManualResetEvent(false);
            var @eventCall2 = new ManualResetEvent(false);
            var @eventCall3 = new ManualResetEvent(false);

            IBatchBuilder factory = RrslLiteConfiguration.Instance.BatchBuilderConfiguration.GetAsyncBatchBuilder();

            factory
                .Call<IPersonFacade>()
                .WithQuery(f => f.GetActivePersonsFor("CZ"), list =>
                                                            {
                                                                Assert.IsNotNull(list);
                                                                @eventCall1.Set();
                                                            })
                .WithQuery(f => f.GetMostImportantPersonFor("DE"), person =>
                                                                  {
                                                                      Assert.IsNotNull(person);
                                                                      @eventCall2.Set();
                                                                  })
                .Call<ICountryFacade>()
                .WithQuery(f => f.GetByCode("CZ"), country =>
                                                  {
                                                      Assert.IsNotNull(country);
                                                      @eventCall3.Set();
                                                  })
                .Execute();

            @eventCall1.WaitOne();
            @eventCall2.WaitOne();
            @eventCall3.WaitOne();

        }

        [TestMethod]
        public void BatchFactoryTEST_VoidAsResult()
        {
            var @eventCall1 = new ManualResetEvent(false);

            IBatchBuilder factory = new AsyncBatchBuilder();

            factory
                .Call<ICountryFacade>()
                .WithCommand(c => c.VoidMethod("sdsd")
                      , () =>
                            {
                                Assert.IsTrue(true);
                                @eventCall1.Set();
                            })
                .Execute();

            @eventCall1.WaitOne();

        }

        [TestMethod]
        public void BatchFactoryAsync_Using_INotifyPropertyChangedInterceptor_Accept_From_Server()
        {
            var @eventCall1 = new ManualResetEvent(false);

            IBatchBuilder factory = RrslLiteConfiguration.Instance.BatchBuilderConfiguration.GetAsyncBatchBuilder();

            factory
                .Call<ICompanyService>()
                .WithQuery(f => f.GetActiveCompanies(), list =>
                {
                    Assert.IsNotNull(list);
                    Assert.IsInstanceOfType(list, typeof (INotifyPropertyChanged));

                    var actualCompany = list.First();
                    Assert.IsInstanceOfType(actualCompany, typeof(INotifyPropertyChanged));
                    Assert.IsInstanceOfType(actualCompany.Addresses, typeof(INotifyPropertyChanged));
                    Assert.IsInstanceOfType(actualCompany.Addresses.First(), typeof(INotifyPropertyChanged));

                    //actualCompany.Addresses = RrslLiteConfiguration.Instance.BatchBuilderConfiguration.
                    //        EntityAopProxyGeneratorConfiguration.CreateProxiedInstance(new List<Address>());

                    actualCompany.Addresses = new List<Address>();
                    actualCompany.Addresses = actualCompany.Addresses.CreateProxy();
                    // filled addresses remains the same
                    Assert.IsInstanceOfType(actualCompany.Addresses, typeof(INotifyPropertyChanged));

                    // not filled collection property is instatiated
                    Assert.IsNotNull(actualCompany.AddressesLowPriority);
                    Assert.IsInstanceOfType(actualCompany.AddressesLowPriority, typeof(INotifyPropertyChanged));

                    @eventCall1.Set();
                })
                .Execute();

            @eventCall1.WaitOne();

        }

        [TestMethod]
        public void BatchFactoryAsync_Using_INotifyPropertyChangedInterceptor_Send_To_Server()
        {
            var @eventCall1 = new ManualResetEvent(false);

            IList<Company> data = null;

            RrslLiteConfiguration.Instance.BatchBuilderConfiguration.GetAsyncBatchBuilder()
                .Call<ICompanyService>()
                .WithQuery(f => f.GetActiveCompanies(), list =>
                {
                    data = list;

                    @eventCall1.Set();

                })
                .Execute();

            @eventCall1.WaitOne();
            @eventCall1.Reset();

            RrslLiteConfiguration.Instance.BatchBuilderConfiguration.GetAsyncBatchBuilder()
                .Call<ICompanyService>()
                .WithCommand(f => f.SetActiveCompany(data.First()), () => @eventCall1.Set())
                .Execute();

            @eventCall1.WaitOne();

        }

        [TestMethod]
        public void BatchFactoryAsync_Calling_ServerService_With_Overloaded_Methods()
        {
            var @eventCall1 = new ManualResetEvent(false);

            RrslLiteConfiguration.Instance.BatchBuilderConfiguration.GetAsyncBatchBuilder()
                .Call<ICompanyService>()
                .WithCommand(f => f.OverloadedMethod(1, 2), () => @eventCall1.Set())
                .Execute();

            @eventCall1.WaitOne();
            @eventCall1.Reset();

            RrslLiteConfiguration.Instance.BatchBuilderConfiguration.GetAsyncBatchBuilder()
                .Call<ICompanyService>()
                .WithCommand(f => f.OverloadedMethod(1), () => @eventCall1.Set())
                .Execute();

            @eventCall1.WaitOne();
            @eventCall1.Reset();

            RrslLiteConfiguration.Instance.BatchBuilderConfiguration.GetAsyncBatchBuilder()
                .Call<ICompanyService>()
                .WithCommand(f => f.OverloadedMethod(), () => @eventCall1.Set())
                .Execute();

            @eventCall1.WaitOne();
        }

        [TestMethod]
        public void BatchFactoryAsync_Calling_ServerService_From_Concurently()
        {
            var @eventCall1 = new ManualResetEvent(false);
            var @eventCall2 = new ManualResetEvent(false);
            var @eventCall3 = new ManualResetEvent(false);

            IBatchBuilder factory = RrslLiteConfiguration.Instance.BatchBuilderConfiguration.GetAsyncBatchBuilder();

            factory
                .Call<IPersonFacade>()
                .WithQuery(f => f.GetActivePersonsFor("CZ"), list =>
                {
                    Assert.IsNotNull(list);
                    @eventCall1.Set();
                })
                .Execute();

            Thread.Sleep(2000);

            factory = RrslLiteConfiguration.Instance.BatchBuilderConfiguration.GetAsyncBatchBuilder();

            factory
                .Call<IPersonFacade>()
                .WithQuery(f => f.GetMostImportantPersonFor("CZ"), list =>
                {
                    Assert.IsNotNull(list);
                    @eventCall2.Set();
                })
                .Execute();

            @eventCall1.WaitOne();
            @eventCall2.WaitOne();
        }
	}
}
